﻿using System;
using System.Data.Objects.DataClasses;
using System.Linq;
using System.Web.Routing;
using Inscriptionem.Authorization;
using Inscriptionem.Extensions;
using Inscriptionem.Models.Enums;
using Inscriptionem.Models.Requests;
using Inscriptionem.Models.Views;

namespace Inscriptionem.Services
{
    public static class InstallService
    {
        public static bool IsDBAvailableAndCorrect
        {
            get
            {
                try
                {
                    var db = new ORM.DB();
                    if (!db.DatabaseExists())
                    {
                        return false;
                    }
                    
                    var language = db.Languages.FirstOrDefault(l => l.IsDefault);
                    return language != null && !string.IsNullOrWhiteSpace(language.Name);
                }
                catch (Exception ex)
                {
                    return false;
                }
            }
        }

        public static void Restart()
        {
            RouteTable.Routes.Clear();
            MvcApplication.RegisterRoutes();
        }

        public static InstallViewModel ValidateInstallRequest(InstallRequestModel Model)
        {
            var result = new InstallViewModel();

            // Apply model
            Model.CopyTo(result);

            if (string.IsNullOrWhiteSpace(result.Language))
            {
                result.Error = InstallError.LanguageEmpty;
            }
            else if (string.IsNullOrWhiteSpace(result.Section))
            {
                result.Error = InstallError.SectionEmpty;
            }
            else if (string.IsNullOrWhiteSpace(result.FirstName))
            {
                result.Error = InstallError.FirstNameEmpty;
            }
            else if (string.IsNullOrWhiteSpace(result.LastName))
            {
                result.Error = InstallError.LastNameEmpty;
            }
            else if (string.IsNullOrWhiteSpace(result.Mail))
            {
                result.Error = InstallError.MailEmpty;
            }
            else if (!result.Mail.Contains("@"))
            {
                result.Error = InstallError.MailNotValid;
            }
            else if (string.IsNullOrWhiteSpace(result.MailConfirmation) || result.Mail != result.MailConfirmation)
            {
                result.Error = InstallError.MailNotMatched;
            }
            else if (string.IsNullOrWhiteSpace(result.Password))
            {
                result.Error = InstallError.PasswordEmpty;
            }
            else if (result.Password.Length < 6)
            {
                result.Error = InstallError.PasswordLength;
            }
            else if (string.IsNullOrWhiteSpace(result.PasswordConfirmation) || result.Password != result.PasswordConfirmation)
            {
                result.Error = InstallError.PasswordNotMatched;
            }

            return result;
        }

        public static bool Install(InstallRequestModel Model)
        {
            var db = new ORM.DB();

            if (Model.RecreateDatabase)
            {
                if (db.DatabaseExists())
                {
                    db.DeleteDatabase();
                }

                db.CreateDatabase();
            }

            DateTime date = DateTime.Now;
            // Add member roles lookup
            foreach (MemberRole role in Enum.GetValues(typeof (MemberRole)))
            {
                if (role == MemberRole.None)
                {
                    continue;
                }

                string roleName = role.ToString();
                db.AddToRoles(new ORM.Role() {ID = (int) role, Name = roleName, Description = roleName, CreatedDate = date, ModifiedDate = date});
            }

            // Add language and section
            var language = new ORM.Language() {Name = Model.Language, LocalizedName = Model.Language, IsDefault = true, Order = 1, CreatedDate = date, ModifiedDate = date};
            var section = new ORM.Section() { Name = Model.Section, LocalizedName = Model.Section, IsDefault = true, Order = 1, CreatedDate = date, ModifiedDate = date };
            language.Sections.Add(section);
            db.AddToLanguages(language);
            db.AddToSections(section);

            db.SaveChanges();

            // Add admin user
            var admin = new ORM.Member()
                            {
                                FirstName = Model.FirstName,
                                NickName = string.IsNullOrWhiteSpace(Model.NickName) ? string.Empty : Model.NickName,
                                LastName = Model.LastName,
                                Mail = Model.Mail.ToLower(),
                                Password = EncryptionService.EncryptString(Model.Mail, Model.Password),
                                BirthDate = DateTime.Now,
                                CreatedDate = date,
                                ModifiedDate = date,
                                IsReadOnly = false,
                                IsRegistrationApproved = true,
                                MemberRole = new EntityCollection<ORM.MemberRole>()
                            };

            var adminSettings = new ORM.MemberSettings()
                                    {
                                        Description = string.Empty,
                                        IsMailVisible = Model.IsMailVisible,
                                        IsBirthDateVisible = Model.IsBirthDateVisible,
                                        IsRealNameVisible = Model.IsRealNameVisible,
                                        SiteLink = string.Empty,
                                        CreatedDate = date,
                                        ModifiedDate = date
                                    };

            admin.MemberSettings = adminSettings;

            var adminRole = new ORM.MemberRole() {Role = db.Roles.First(r => r.ID == (int)MemberRole.Admin)};
            admin.MemberRole.Add(adminRole);
                
            db.AddToMembers(admin);
            db.AddToMemberSettings(adminSettings);
            db.AddToMemberRoles(adminRole);

            db.SaveChanges();
            return true;
        }
    }
}